home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_100
/
134_01
/
cprofile.c
< prev
next >
Wrap
Text File
|
1985-08-19
|
19KB
|
765 lines
/* CPROFILE -- BDS `C' Program Profiler */
/* Copyright (c) 1983 by Kevin B. Kenny
Released to the BDS `C' Users' Group for non-commercial distribution.
Kevin Kenny
729-A E. Cochise Dr.
Phoenix, Arizona 85020
*/
#define TITLE "CPROFILE version 83-11-14 copyright (c) 1983 by Kevin Kenny\n"
#include "bdscio.h"
#include "dio.h"
#include "cmdutil.h"
/* Configuration */
#define TOP 0x7000 /* End of usable memory. Must be supplied
to CLINK or L2 with the '-t' option. */
/* Define some general-purpose pointers */
union ptr {
unsigned i; /* Integer representation */
unsigned * w; /* Word pointer */
char * b; /* Byte pointer */
};
/* Define a long integer for the LONG.C package. */
struct longint {
char longcont [4];
};
#define LONG struct longint /* Poor man's TYPEDEF */
/* Define the structure of the execution profile table */
struct proftab {
unsigned pfaddr; /* PC of the RST 6 operation */
LONG pftimes; /* Number of times that RST was hit. */
} * ptent;
/* Define the structure of the beginning of the run-time RST 6
interceptor/supervisor */
struct supvsr {
char supjmp0; /* A JMP (0xC3) instruction */
unsigned supbdos; /* Entry to CP/M BDOS (where the JMP goes) */
char supname [9]; /* 'cprofile' monogram to detect re-entry */
char supjmp1; /* Another JMP (0xC3) instruction */
unsigned supinit; /* Initialization entry into supervisor */
char supjmp2; /* Another JMP (0xC3) instruction */
unsigned supboot; /* Fake warmboot entry into supervisor */
unsigned suptop; /* Upper address of the supervisor */
struct proftab * supent1; /* Pointer to first entry in profile */
struct proftab * supnxte; /* Pointer to next avail entry */
unsigned supbios; /* Address to restore to BIOS transfer */
char supcmd [128]; /* CPROFILE command line saved for reload */
};
union {
struct supvsr * sps; /* Pointer to the supervisor */
void (* spf) ();
unsigned spi; /* Integer value thereof */
} suprvp;
/* Define the command line options */
struct option optable [5]; /* Place to put the option table */
int tabsize; /* Size of the profile table needed */
int pagelen; /* Printer page length */
int nsrcfs; /* Number of source files supplied */
char * * sfiles; /* Names of the source files */
char * srcfnptr [2]; /* Default source file pointer */
char srcfnam [20]; /* Default source file */
/* Define the I/O environment */
char * prgnam; /* Name of the program being analyzed*/
char comfnam [20]; /* Name of the .COM file */
char comfile [134]; /* I/O stream for the .COM file */
char symfnam [20]; /* Name of the .SYM file */
FILE symfile; /* CHARIO stream for the .SYM file */
FILE srcfile; /* Input stream for the source file */
/* Working storage */
int hisargc; /* ARGC of profiled program */
char ** hisargv; /* ARGV of profiled program */
char pass2; /* Flag = TRUE iff in analysis pass */
char fnname [9]; /* Name of function being analyzed */
int stmt; /* Statement number within function */
int line; /* Line number within function */
char symfnnam [9]; /* Last function read from .SYM */
unsigned symtopad; /* Upper address of last .SYM funct */
char symend; /* Flag == TRUE if at end of .SYM */
char sfopen; /* Flag == TRUE if a source file open*/
char seof; /* FLAG == TRUE at end of source file*/
int slevel; /* Depth of {} nesting in source */
char sname [33]; /* Name of a symbol in source */
char infunct; /* Flag == TRUE if in funct in src */
int sline; /* Relative line # in source funct. */
char slopen; /* Flag == TRUE if in source line */
int linage; /* Number of lines on current page */
int pageno; /* Current page # */
/* Main program */
main (argc, argv)
int argc;
char * * argv;
{
union ptr bdosp;
/* Test if CPROFILE is active. If it is, this must be the second pass.
*/
pass2 = FALSE;
prgnam = argv [1]; /* Rem,ember the program name */
bdosp.i = 6; /* Point to the BDOS entry address in lowcore*/
suprvp.spi = *bdosp.w; /* Get the BDOS entry address (top of TPA) */
if (!strcmp (suprvp.sps -> supname, "cprofile")) pass2 = TRUE;
/* Scan the command line, separating CPROFILE's arguments from
the target program's. */
hisargv = argv = argv + 1; hisargc = 0; /* His args start at once */
--argc;
while (argc && strcmp (*argv, ":")) { /* My args start with a ":" */
++argv; --argc; ++hisargc;
}
if (pass2) dioinit (&argc, argv);
/* Process command line options */
getopts (argc, argv);
/* Call appropriate analysis routines */
if (pass2) {
/* Second pass -- call the analyzer */
analyze (argc, argv);
}
else {
/* First pass -- install supervisor and call in program to
be profiled */
if (!hisargc) {
fprintf (STD_ERR, "Command must be supplied.\n");
goto synerr;
}
fprintf (STD_ERR, TITLE);
install ();
fprintf (STD_ERR, "<<< Loading target program. >>>\n");
chain (hisargc, hisargv, &(suprvp.sps -> supjmp1));
}
synerr:
dioflush ();
}
/* Process command line options */
getopts (argc, argv)
int argc;
char ** argv;
{
char error; /* Flag = TRUE iff command erroneous */
union {
int ii;
char * si;
char * * msi;
} info;
/* Define the available options */
initv (optable, EOF,
#define STRG_OPT -1
"Linecount", NVAL_KWD,
#define LCNT_OPT 0
"PageLength", NVAL_KWD,
#define PLEN_OPT 1
"SourceFiles", MSVL_KWD,
#define SFIL_OPT 2
EOF);
++argv; --argc; /* Discard colon separator */
error = FALSE;
tabsize = 512 * sizeof ptent;
pagelen = 58;
srcfnptr [1] = & srcfnam;
strcpy (srcfnam, hisargv [0]);
makeext (srcfnam, "C");
sfiles = & srcfnptr;
nsrcfs = 1;
while (argc > 0) {
switch (procarg (&argc, &argv, optable, &info)) {
case STRG_OPT:
break; /* Discard redirection */
case LCNT_OPT:
tabsize = info.ii * sizeof (* ptent);
break;
case PLEN_OPT:
pagelen = info.ii;
break;
case SFIL_OPT:
nsrcfs = * (sfiles = info.msi);
break;
default:
error=TRUE;
}
}
if (error || hisargc < 1) {
showsyntax ("cprofile <command and options> : [>filename]",
optable);
quit ();
}
}
/* Install CPROFILE in the top of the TPA */
install () {
struct ptr p, q; /* Working pointer */
void superv (); /* The supervisor's code */
unsigned * supervrl (); /* The supervisor's relocation table */
unsigned suprvs; /* Size of the supervisor */
unsigned offset; /* Relocation factor for supervisor */
unsigned nrelocs; /* Number of relocated words in sup */
/* Find the top of the TPA. Using this, the size of the supervisor,
and the size of the profile table, find where the supervisor origin
will be. */
p.i = 6; /* Get address of BDOS jump + 1 */
p.i = *p.w; /* Get address of TPA top. */
suprvp.spf = &superv; /* Point to current supervisor origin*/
suprvs = suprvp.sps -> suptop - suprvp.spi;
/* Get its length */
p.i = (p.i - suprvs - tabsize) & 0xFF00;
/* Find new supervisor origin */
if (p.i < TOP) {
fprintf (STD_ERR,
"Profile table overlays CPROFILE; use smaller -L\n");
quit ();
}
/* Move the supervisor into place */
offset = p.i - suprvp.spi;
movmem (suprvp.spi, p.i, suprvs);
suprvp.spi = p.i;
/* Relocate the supervisor */
p.w = supervrl (); /* Get relocation table */
nrelocs = *p.w++;
while (nrelocs--) {
q.i = suprvp.spi + *p.w++; /* Get a relocation address */
*q.w += offset; /* Relocate it */
}
/* Link the BDOS transfer through the supervisor */
p.i = 6;
suprvp.sps -> supbdos = *p.w;
*p.w = suprvp.spi;
/* Link the BIOS warmboot transfer through the supervisor */
p.i = 1;
p.i = *p.w + 1;
suprvp.sps -> supbios = *p.w;
*p.w = &(suprvp.sps -> supjmp2);
/* Record the CPROFILE command line in the supervisor for reload*/
movmem (0x0080, &(suprvp.sps -> supcmd), 128);
}
/* Analyze the results of a profiled run */
an